﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using Fleck;
using Newtonsoft.Json;

namespace WebSocketDemo.Tools
{
    public class WebSocketHelper
    {

        private static WebSocketHelper _webSocketHelperInstance = null;

        /// <summary>
        /// 获取实例
        /// </summary>
        public static WebSocketHelper GetInstance()
        {
            if (_webSocketHelperInstance == null)
            {
                _webSocketHelperInstance = new WebSocketHelper();
            }

            return _webSocketHelperInstance;
        }

        private List<IWebSocketConnection> _allSockets = new List<IWebSocketConnection>();

        private WebSocketHelper()
        {
            FleckLog.Level = LogLevel.Info;
            var server = new WebSocketServer("ws://0.0.0.0:7181");//任意IP
            server.Start(socket =>
            {
                var str = string.Empty;
                socket.OnOpen = () =>
                {
                    Console.WriteLine("Open!");
                    AddSocket(socket);
                    _allSockets.Add(socket);
                };
                socket.OnClose = () =>
                {
                    Console.WriteLine("Close!");
                    RemoveSocket(socket);
                    _allSockets.Remove(socket);
                };
                socket.OnMessage = message =>
                {
                    str = message;
                    MessageModel model = null;
                    try
                    {
                        model = message.ToObject<MessageModel>();
                        if (model.IsNotNull())
                        {
                            switch (model.Type)
                            {
                                case 0:// 0.关联用户与当前连接
                                    UserInfoHelper.AddConnectionId(model, socket.ConnectionInfo.Id);
                                    var resp = new RespModel
                                    {
                                        MessageContent = "关联成功",
                                        MessageId = string.Empty,
                                        MessageTitle = "关联成功",
                                        MessageType = 0,
                                        ToUrl = string.Empty,
                                        NeedToJump = false
                                    };
                                    socket.Send(resp.ToJson()); //通知客户端关联成功
                                    break;
                                case 1:// 1.发送消息给全部的用户(排除自己)
                                    var resp1 = new RespModel
                                    {
                                        MessageContent = model.MessageContent,
                                        MessageId = string.Empty,
                                        MessageTitle = "用户对话",
                                        MessageType = 0,
                                        ToUrl = string.Empty,
                                        NeedToJump = false
                                    }.ToJson();
                                    _allSockets = _allSockets.Where(s => s.ConnectionInfo.Id != socket.ConnectionInfo.Id).ToList();
                                    _allSockets.ToList().ForEach(s => s.Send(resp1));
                                    break;
                                case 2:// 2.发送消息到指定的模块
                                    var users = UserInfoHelper.GetModelConnections(model.ModelCode);
                                    var connectionIds = users.Select(u => u.ConnectionId).ToList();
                                    var sockets = _allSockets.Where(s => connectionIds.Contains(s.ConnectionInfo.Id)).ToList();

                                    var resp2 = new RespModel
                                    {
                                        MessageContent = model.MessageContent,
                                        MessageId = string.Empty,
                                        MessageTitle = "用户对话",
                                        MessageType = 0,
                                        ToUrl = string.Empty,
                                        NeedToJump = false
                                    }.ToJson();
                                    sockets.ForEach(s=>s.Send(resp2));
                                    break;
                                case 3://3.发送消息到指定的用户
                                    var userList = UserInfoHelper.GetUserConnections(model.UserIdList);
                                    var connectionIdList = userList.Select(u => u.ConnectionId).ToList();
                                    var socketList = _allSockets.Where(s => connectionIdList.Contains(s.ConnectionInfo.Id)).ToList();
                                    var resp3 = new RespModel
                                    {
                                        MessageContent = model.MessageContent,
                                        MessageId = string.Empty,
                                        MessageTitle = "用户对话",
                                        MessageType = 0,
                                        ToUrl = string.Empty,
                                        NeedToJump = false
                                    }.ToJson();
                                    socketList.ForEach(s => s.Send(resp3));
                                    break;
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine(e);
                        var resp1 = new RespModel
                        {
                            MessageContent = "消息格式不正确，请检查你的消息内容格式是否正确",
                            MessageId = string.Empty,
                            MessageTitle = "错误提示",
                            MessageType = -1,
                            ToUrl = string.Empty,
                            NeedToJump = false
                        }.ToJson();
                        socket.Send(resp1);
                    }

                };
                socket.OnBinary = file =>
                {

                    var virtualPath = "/UploadFile/Files/";
                    var directory = $"{AppDomain.CurrentDomain.BaseDirectory}{virtualPath}";
                    if (!Directory.Exists(directory))
                    {
                        Directory.CreateDirectory(directory);
                    }

                    var path = $"{directory}{DateTime.Now:yyyyMMddHHmmss}{str}";

                    //string path = ("E:/15-烟厂项目/07-Poc/WebSocketDemo/test.txt");
                    //创建一个文件流
                    FileStream fs = new FileStream(path, FileMode.Create);

                    //将byte数组写入文件中
                    fs.Write(file, 0, file.Length);
                    //所有流类型都要关闭流，否则会出现内存泄露问题
                    fs.Close();
                };
            });
        }


        private string socketCacheKey = "_allSockets";

        /// <summary>
        /// 把当前socket链接保存到内存
        /// </summary>
        /// <param name="socket"></param>
        public void AddSocket(IWebSocketConnection socket)
        {
            var cache = CacheHelper.GetCache(socketCacheKey);
            if (cache.IsNull())
            {
                var allSockets = new List<IWebSocketConnection> { socket };
                CacheHelper.SetCache(socketCacheKey, allSockets);
            }
            else
            {
                var allSockets = (List<IWebSocketConnection>)cache;
                allSockets.Add(socket);
                CacheHelper.SetCache(socketCacheKey, allSockets);
            }
        }

        /// <summary>
        /// 从内存中移除该链接
        /// </summary>
        public void RemoveSocket(IWebSocketConnection socket)
        {
            var cache = CacheHelper.GetCache(socketCacheKey);
            if (cache.IsNotNull())
            {
                var allSockets = (List<IWebSocketConnection>)cache;
                allSockets = allSockets.Where(s => s.ConnectionInfo.Id != socket.ConnectionInfo.Id).ToList();
                CacheHelper.SetCache(socketCacheKey, allSockets);
            }
        }

        public void SendMsg(MessageModel model)
        {
            var resp = new RespModel
            {
                MessageContent = model.MessageContent,
                MessageId = string.Empty,
                MessageTitle = "用户对话",
                MessageType = 0,
                ToUrl = string.Empty,
                NeedToJump = false
            }.ToJson();
            if (string.IsNullOrEmpty(model.MessageContent))
                return;

            switch (model.Type)
            {
                case 1:
                    break;
                case 2:
                    var users = UserInfoHelper.GetModelConnections(model.ModelCode);
                    var connectionIds = users.Select(u => u.ConnectionId).ToList();
                    _allSockets = _allSockets.Where(s => connectionIds.Contains(s.ConnectionInfo.Id)).ToList();
                    break;
                case 3:
                    var userList = UserInfoHelper.GetUserConnections(model.UserIdList);
                    var connectionIdList = userList.Select(u => u.ConnectionId).ToList();
                    _allSockets = _allSockets.Where(s => connectionIdList.Contains(s.ConnectionInfo.Id)).ToList();
                    break;
            }

            foreach (var socket in _allSockets.ToList())
            {
                socket.Send(resp);
            }
        }
    }

    /// <summary>
    /// 消息实体
    /// </summary>
    public class MessageModel
    {
        /// <summary>
        /// 0.关联用户与当前连接，1.发送消息给全部的用户，2.发送消息到指定的模块，3.发送消息到指定的用户
        /// </summary>
        public int Type { set; get; }

        /// <summary>
        /// 当前用户标识
        /// </summary>
        public string Token { set; get; }

        /// <summary>
        /// 模块编码
        /// </summary>
        public string ModelCode { set; get; }

        /// <summary>
        /// 消息接收用户列表
        /// </summary>
        public List<string> UserIdList { set; get; }

        /// <summary>
        /// 消息内容
        /// </summary>
        public string MessageContent { set; get; }
    }

    /// <summary>
    /// 返回消息实体
    /// </summary>
    public class RespModel
    {
        /// <summary>
        /// 消息id
        /// </summary>
        public string MessageId { set; get; }

        /// <summary>
        /// 消息内容
        /// </summary>
        public string MessageContent { set; get; }

        /// <summary>
        /// 跳转地址
        /// </summary>
        public string ToUrl { set; get; }

        /// <summary>
        /// 是否需要跳转
        /// </summary>
        public bool NeedToJump { set; get; }

        /// <summary>
        /// 消息标题
        /// </summary>
        public string MessageTitle { set; get; }

        /// <summary>
        /// 消息类型：-1.提示,0.对应接收消息的类型0，告诉客户端，服务器端收到了，1.出库消息，2.巡检消息，3.异常消息，4.维修消息
        /// </summary>
        public int MessageType { set; get; }

    }
}
